/*********** CLIENTE ************/
/* Encoding: UTF8 */

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>

void quickSort( int a[], int l, int r)
{
   int j;

   if( l < r ) 
   {
    // divide and conquer
        j = partition( a, l, r);
       quickSort( a, l, j-1);
       quickSort( a, j+1, r);
   } 
}

int partition( int a[], int l, int r) {
   int pivot, i, j, t;
   pivot = a[l];
   i = l; j = r+1;
    
   while(1)
   {
    do ++i; while( a[i] <= pivot && i <= r );
    do --j; while( a[j] > pivot );
    if( i >= j ) break;
    t = a[i]; a[i] = a[j]; a[j] = t;
   }
   t = a[l]; a[l] = a[j]; a[j] = t;
   return j;
}

int main(int argc, char *argv[ ])
{
   // Variáveis
   int sock, bytes_recv, i;
   int vector[1250], vectorout[1250], sortedvector[10000];
   struct hostent *host;
   struct sockaddr_in server_addr;
   // Contadores de tempo
   struct timeval total_time_begin, total_time_end;
   struct timeval ordering_time_begin, ordering_time_end;
   struct timeval connection_time_begin, connection_time_end;
   double total_time_spent, ordering_time_spent, connection_time_spent;

   // Checa argumentos da linha de comando
   if(argc < 3){
      printf("Uso : %s <servidor> <porta> \n", argv[0]);
      exit(1);
   }

   // Inicia contagem do tempo total do processo
   gettimeofday(&total_time_begin, NULL);

   // Gera o vetor aleatório de 1250 posições
   srand(time(0));

   for(i = 0; i < 1250; i++)
   {
      vector[i] = rand()%50000;
      vectorout[i] = vector[i];
   }

   // Inicia contagem do tempo de ordenação do vetor
   gettimeofday(&ordering_time_begin, NULL);

   quickSort(vectorout, 0, 1249);

   // Termina contagem do tempo de ordenação do vetor
   gettimeofday(&ordering_time_end, NULL);
   
   // Inicia contador de tempo de conexão
   gettimeofday(&connection_time_begin, NULL);

   // Cria conexão com o servidor de nível 1
   host = gethostbyname(argv[1]);
   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
   {
      perror("Erro de Socket");
      exit(1);
   }

   server_addr.sin_family = AF_INET;
   server_addr.sin_port = htons(atoi(argv[2]));
   server_addr.sin_addr = *((struct in_addr *)host->h_addr);
   bzero(&(server_addr.sin_zero),8);

   if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
   {
      perror("Erro de conexao");
      exit(1);
   }

   // Envia o vetor gerado ao servidor
   send(sock, vector, sizeof(int)*1250, 0);

   // Recebe o vetor final ordenado
   recv(sock, sortedvector, sizeof(int)*10000, 0);

   // Termina contagem do tempo de conexão
   gettimeofday(&connection_time_end, NULL);

   // Imprime o vetor gerado no cliente
   printf("Vetor gerado: [ ");
   for (i = 0; i < 1250; i++)
   {
      printf("%d ", vector[i]);
   }
   printf("]\n");

   // Imprime vetor ordenado no cliente
   printf("Vetor gerado: [ ");
   for (i = 0; i < 1250; i++)
   {
      printf("%d ", vectorout[i]);
   }
   printf("]\n");

   // Imprime vetor ordenado na tela
   printf("Vetor final: [ ");
   for (i = 0; i < 10000; i++)
   {
      printf("%d ", sortedvector[i]);
   }
   printf("]\n");
   
   // Termina a contagem do tempo total do processo
   gettimeofday(&total_time_end, NULL);

   ordering_time_spent = ((ordering_time_end.tv_sec - ordering_time_begin.tv_sec)*10000000L + ordering_time_end.tv_usec) - ordering_time_begin.tv_usec;
   connection_time_spent = ((connection_time_end.tv_sec - connection_time_begin.tv_sec)*10000000L + connection_time_end.tv_usec) - connection_time_begin.tv_usec;
   total_time_spent = ((total_time_end.tv_sec - total_time_begin.tv_sec)*10000000L + total_time_end.tv_usec) - total_time_begin.tv_usec;

   printf("Tempo de ordenação do vetor: %.2lf ms\n", ordering_time_spent / 10000);
   printf("Tempo de conexão com o servidor: %.2lf ms\n", connection_time_spent / 10000);
   printf("Tempo total: %.2lf ms\n", total_time_spent / 10000);

   // Fecha o socket
   close(sock);
   return 0;
}

